package com.cskt.petums.service.redis;

import com.cskt.common.entity.vo.StatusEnum;
import com.cskt.common.exception.BaseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * redis相关的service层
 *
 * @author admin
 * &#064;date  2023/05/18 17:18
 **/
@Service
public class RedisService {

    private static final Logger log = LoggerFactory.getLogger(RedisService.class);

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ObjectMapper objectMapper;

    /**
     * 存储K-V
     *
     * @param key 键
     * @param value 值
     */
    public void putValue(String key, String value) {
        try {
            ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
            valueOps.set(key, value);
            log.info("put key:{} value:{}", key, value);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 存储Key-Value
     *
     * @param key 键 
     * @param value 值 
     * @param timeOut 过期时间
     */
    public void putValue(String key, String value, Integer timeOut) {
        try {
            ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
            opsForValue.set(key, value, timeOut, TimeUnit.SECONDS);
            log.info("put key:{} value:{} timeOut:{} second", key, value, timeOut);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 批量存储key-value
     *
     * @param values 键值对集合
     */
    public void putValue(Map<String, String> values) {
        try {
            ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
            opsForValue.multiSet(values);
            log.info("put map:{}", values);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 获取key的有效期
     *
     * @param key 键
     */
    public Long getExpireTime(String key) {
        try {
            if (!StringUtils.hasText(key)) {
                return null;
            }
            return stringRedisTemplate.getExpire(key);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 获取value
     *
     * @param key 键
     *
     * @return 不存在时，返回null
     *
     */
    public String getValue(String key) {
        String result = null;
        try {
            ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
            return valueOps.get(key);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 批量获取值
     *
     * @param keys 键集合
     *
     * @return 对应的值
     */
    public Map<String, String> multiGetValue(List<String> keys) {
        Map<String, String> results;
        try {
            ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
            List<String> values = valueOps.multiGet(keys);
            results = new HashMap<>(16);
            if (!CollectionUtils.isEmpty(values) && !keys.isEmpty()) {
                for (int i = 0; i < keys.size(); i++) {
                    String fieldName = keys.get(i);
                    String fieldValue = values.get(i);
                    // 如果对应的字段为null，则不需要放入
                    if (StringUtils.hasText(fieldValue)) {
                        results.put(fieldName, fieldValue);
                    }
                }
            }
            return results;
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 批量删除key
     *
     * @param keys 键集合
     *
     */

    public void delete(Collection<String> keys) {
        try {
            stringRedisTemplate.delete(keys);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 删除key
     *
     * @param key 待删除的键
     *
     */
    public void delete(String key) {
        try {
            stringRedisTemplate.delete(key);
            log.info("delete key:{}", key);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 更新hash里面的属性字段
     *
     * @param key     键
     * @param hashKey 属性名称
     * @param value   属性值
     *
     */
    public int putHash(String key, String hashKey, String value) {
        int succ;
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            hashOps.put(key, hashKey, value);
            succ = 1;
            log.info("put hash key={},hashKey={},value={}", key, hashKey, value);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return succ;
    }

    /**
     * 批量更新hash里面的属性字段
     *
     * @param key 键
     * @param hashProperties 属性集合
     *
     */
    public void putHash(String key, Map<String, String> hashProperties) {
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            hashOps.putAll(key, hashProperties);
            log.info("put hash key:{},hashKey-value:{}", key, hashProperties);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 获取hash的字段值
     *
     * @param key 键
     * @param hashKey hash中的键
     *
     */
    public String getHash(String key, String hashKey) {
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            String result = hashOps.get(key, hashKey);
            return !StringUtils.hasText(result) ? null : result;
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 批量获取hash的字段值
     * @param key
     * @param hashKeys
     * @return filed的Map集合, filedName-filedValue
     */
    public Map<String, String> multiGetHash(String key, List<String> hashKeys) {
        HashMap<String, String> results = null;
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            List<String> values = hashOps.multiGet(key, hashKeys);
            results = new HashMap<>();
            if (!CollectionUtils.isEmpty(values)) {
                for (int i = 0; i < hashKeys.size(); i++) {
                    String fieldName = hashKeys.get(i);
                    String fieldValue = values.get(i);
                    // 如果对应的字段为null，则不需要放入
                    if (StringUtils.hasText(fieldValue)) {
                        results.put(fieldName, fieldValue);
                    }
                }
            }
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return results;
    }

    /**
     * 获取结果
     * @param key
     * @return
     */
    public Map<String, String> getHashValues(String key) {
        Map<String, String> results = null;
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            results = hashOps.entries(key);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }

        return results;
    }

    /**
     * 从hash表里面删除对应的值
     * @param key
     * @param hashKey
     * @throws Exception
     */
    public int deleteHash(String key, String hashKey) {
        int succ = 0;
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            hashOps.delete(key, hashKey);
            succ = 1;
            log.info("delete hash key:{}, hashKey:{}", key, hashKey);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return succ;
    }

    /**
     * 为Hash表中指定的hashKey增加指定大小
     *
     * @param key
     * @param hashKey
     * @param l       增量
     *
     * @throws Exception
     */
    public Long increment(String key, String hashKey, long l) {
        Long increment = null;
        try {
            HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
            increment = hashOps.increment(key, hashKey, l);
            log.info("delete hash key:{}, hashKey:{}", key, hashKey);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return increment;
    }

    /**
     * 为key设置超时时间
     *
     * @param key
     * @param timeout
     */
    public void expire(String key, long timeout) {
        try {
            boolean expire = Boolean.TRUE.equals(stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS));
            if (expire) {
                log.info("Expire success key:{}, timeout:{}", key, timeout);
            } else {
                log.info("Expire fail key:{}, timeout:{}", key, timeout);
            }
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 进行递增
     *
     * @param key
     * @param delta
     * @param timeout
     *
     * @return
     *
     * @throws Exception
     */
    public long incrementDelta(String key, long delta, long timeout) {
        long result = -1L;
        try {
            ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
            result = valueOps.increment(key, delta);
            stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
            log.info("increment key:{}, result:{}, timeout:{}", key, result, timeout);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return result;
    }

    /**
     * 进行递增
     *
     * @param key
     * @param delta
     *
     * @return
     *
     * @throws Exception
     */
    public long incrementDelta(String key, long delta) {
        long result = -1L;
        try {
            ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
            result = valueOps.increment(key, delta);
            log.info("increment key:{}, result:{}", key, result);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return result;
    }

    /**
     * 将集合放到list中
     */
    public List<String> getList(String key, long start, long end) {
        List<String> result = null;
        try {
            ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
            result = opsForList.range(key, start, end);
            log.info("getList list key:{},result:{}", key, result);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return result;
    }

    /**
     * 将集合放到list中
     */
    public void leftPushList(String key, List<String> list) {
        try {
            ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
            opsForList.leftPushAll(key, list);
            log.info("leftPush list key:{},value:{}", key, list);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }


    /**
     * 从左推送到list中
     */
    public void leftPush(String key, String value) {
        try {
            BoundListOperations<String, String> stringStringBoundListOperations = stringRedisTemplate.boundListOps(key);
            stringStringBoundListOperations.leftPush(value);
            log.info("leftPush list key:{},value:{}", key, value);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 从list左边弹出
     */
    public String leftPop(String key) {
        String result = null;
        try {
            ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
            result = opsForList.leftPop(key);
            log.info("leftPop list key:{},result:{}", key, result);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return result;
    }

    /**
     * 从list右边弹出
     */
    public String rightPop(String key) {
        String result = null;
        try {
            BoundListOperations<String, String> stringStringBoundListOperations = stringRedisTemplate.boundListOps(key);
            result = stringStringBoundListOperations.rightPop();
            log.info("rightPop list key:{},result:{}", key, result);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
        return result;
    }

    public Object get(String key) {
        return key == null ? null : stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     *
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            stringRedisTemplate.opsForValue().set(key, value.toString());
            return true;
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }

    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     *
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                stringRedisTemplate.opsForValue().set(key, value.toString(), time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    public <T> T getJson(String key, Class<T> entityClass) {
        try {
            String value = getValue(key);
            if (!StringUtils.hasText(value)) {
                return null;
            }
            return objectMapper.readValue(value, entityClass);
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    public boolean setJson(String key, Object value, Integer time) {
        try {
            if (time > 0) {
                putValue(key, objectMapper.writeValueAsString(value), time);
            } else {
                putValue(key, objectMapper.writeValueAsString(value));
            }
            return true;
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    public <T> List<T> getJsonList(String key, Class<T> entityClass) {
        try {
            String value = getValue(key);
            if (!StringUtils.hasText(value)) {
                return null;
            }
            return objectMapper
                    .readValue(value,objectMapper.getTypeFactory().constructCollectionLikeType(List.class, entityClass));
        } catch (Exception e) {
            log.error("redis service exception:{}", e.getMessage());
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }


}
